#include <iostream>
#include <vector>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <memory>
#include <functional>

class ThreadPool {
public:
    using Functor = std::function<void(void)>;

    ThreadPool(int thread_count = 1) : _stop(false) {
        for (int i = 0; i < thread_count; i++) {
            _threads.emplace_back(&ThreadPool::entry, this); // 调用thread构造函数 template <class Fn, class... Args>explicit thread (Fn&& fn, Args&&... args);
        }
    }
    ~ThreadPool() {
        stop();
    }
    void stop() {
        if (_stop == true)  // 若标志位置为true, 则不重复执行线程池停止操作
            return;
        
        // 将停止标志位置为true，并唤醒所有线程进行等待
        _stop = true;
        _cv.notify_all();
        for (auto &thread : _threads) {
            thread.join();
        }
    }

    // push函数首先需要传入一个函数 -- 用户要执行的任务, 接下来是不定参, 表示要处理的任务中的参数
    // push函数内部会将这个传入的函数封装成一个异步任务（packaged_task）
    // 使用lambda生成一个可调用对象, 抛入到任务池中, 由工作线程取出进行执行
    template<typename F, typename ...Args>
    auto push(const F&& func, Args&& ...args) -> std::future<decltype(func(args...))> {
        // 1. 将传入的函数封装成一个packaged_task对象
        using return_type = decltype(func(args...));    // 推导传入函数的返回值类型
        auto tmp_func = std::bind(std::forward<F>(func), std::forward<Args>(args)...);  // 为什么需要完美转发
        auto task = std::make_shared<std::packaged_task<return_type()>>(tmp_func);
        std::future<return_type> fu = task->get_future();    // 
        // 2. 构造一个lambda匿名函数, 函数内执行任务对象, 并抛入到任务池中
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _taskpool.push_back([task](){
                (*task)();
            });
            _cv.notify_one();   // 唤醒一个线程
        }

        return fu;
    }

private:
    // 线程入口函数 -- 内部不断的从任务池中取出任务进行执行
    void entry() {
        while(!_stop) {
            std::vector<Functor> tmp_taskpool;
            {
                // 加锁
                std::unique_lock<std::mutex> lock(_mutex);
                // 等待任务池不为空，或者
                _cv.wait(lock, [this]() {   // 条件变量的wait函数不太理解？
                    return _stop || !_taskpool.empty();
                });
                // 取出任务进行执行
                tmp_taskpool.swap(_taskpool);
            }
            for (auto &task : tmp_taskpool) {
                task();
            }
        }
    }
private:
    std::vector<Functor> _taskpool;
    std::mutex _mutex;
    std::condition_variable _cv;
    std::vector<std::thread> _threads;
    std::atomic<bool> _stop;
};

int Add(int num1, int num2) {
    return num1 + num2;
}

int main()
{
    ThreadPool pool(2);
    for (int i = 0; i < 10; i++) {
        std::future<int> fu = pool.push(Add, 11, i);
        std::cout << fu.get() << std::endl;
    }
    pool.stop();
    return 0;
}